﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Collections.TreeCollections
{
    public class TreeRegisterClass
    {
        #region Properties
        public Type TreeType { get; protected set; }
        public TreeObjectRegisterClass this[Type index] { get { return (TreeObjectRegisterClass)_registerTable[index]; } }
        public TreeObjectRegisterClass this[string index] { get { return getRegisterClass(index); } }
        public Type[] Keys { get { return getKeys(); } }
        public TreeObjectRegisterClass[] Values { get { return getValues(); } }

        public ConstructTree TreeConstructor { get; protected set; }
        public ConstructTreeWithRoot TreeConstructorRoot { get; protected set; }
        public TreeXmlParse XmlParser { get; protected set; }
        public TreeObjectRegisterClass TreeRootRegister { get { return getRootRegisterClass(); } }
        
        /// <summary>
        /// The list contains the object type information which this tree support.
        /// Key: Type
        /// Value: TreeObjectInfo
        /// </summary>
        private Hashtable _registerTable;
        #endregion
        /// <summary>
        /// 
        /// </summary>
        /// <param name="treeType">Type must inherit from Tree</param>
        public TreeRegisterClass(Type treeType, ConstructTree constructor
            , ConstructTreeWithRoot constructorRoot
            , TreeXmlParse xmlParser)
        {
            // check type
            if(!treeType.IsSubclassOf(typeof(Tree)))
            {
                throw new Exception("Tree type must derives from Tree");
            }

            TreeType = treeType;
            TreeConstructor = constructor;
            TreeConstructorRoot = constructorRoot;
            XmlParser = xmlParser;
            _registerTable = new Hashtable();
        }

        /// <summary>
        /// Register tree object class.
        /// The Tree Register can only contain one Tree Register Class.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="registerClass"></param>
        public void RegisterTreeObjectType(TreeObjectRegisterClass registerClass)
        {
            if (registerClass.TreeObjectType.IsSubclassOf(typeof(TreeRoot))
                && getRootRegisterClass() != null)
            {
                throw new TreeRegisterException(
                    "Tree Register can be registered only one TreeRoot.");
            }

            _registerTable.Add(registerClass.TreeObjectType
                , registerClass);
        }

        /// <summary>
        /// Get Keys
        /// </summary>
        /// <returns></returns>
        private Type[] getKeys()
        {
            Type[] keys = new Type[_registerTable.Count];
            int index = 0;
            foreach (Type type in _registerTable.Keys)
            {
                keys[index++] = type;
            }
            return keys;
        }
        /// <summary>
        /// Get Values
        /// </summary>
        /// <returns></returns>
        private TreeObjectRegisterClass[] getValues()
        {
            TreeObjectRegisterClass[] values = new TreeObjectRegisterClass[_registerTable.Count];
            int index = 0;
            foreach (TreeObjectRegisterClass obj in _registerTable.Values)
            {
                values[index++] = obj;
            }
            return values;
        }
        /// <summary>
        /// Get type
        /// </summary>
        /// <param name="typeStr"></param>
        /// <returns></returns>
        private TreeObjectRegisterClass getRegisterClass(string typeStr)
        {
            Type type = null;
            foreach (Type tmpType in this.Keys)
            {
                if (tmpType.FullName == typeStr)
                {
                    type = tmpType;
                    break;
                }
            }
            return this[type];
        }
        /// <summary>
        /// Get root register class
        /// </summary>
        /// <returns></returns>
        private TreeObjectRegisterClass getRootRegisterClass()
        {
            foreach (Type type in this.Keys)
            {
                if(type.IsSubclassOf(typeof(TreeRoot)))
                {
                    return this[type];
                }
            }
            return null;
        }
    }
}
